﻿/***********************************************************************************************//**
*\n  @file       netcan.c
*\n  @brief      can通讯驱动模块接口
*\n  @details
*\n -----------------------------------------------------------------------------------
*\n  文件说明：
*\n       1. can通讯驱动模块接口
*\n
*\n -----------------------------------------------------------------------------------
*\n  版本:   修改人:       修改日期:        描述:
*\n  V0.01 罗先能        2021.4.7    创建
*\n  V0.02 罗先能        2021.7.7    添加读写锁等
*\n
***************************************************************************************************/

/**************************************************************************************************
* 头文件
***************************************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <libgen.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <fcntl.h>
#include <pthread.h>

#include "socketcan.h"
#include "netcan.h"

#undef   DEBUG_LEVEL
#define  DEBUG_LEVEL  5
#include "vdebug.h"


/**************************************************************************************************
* 宏定义、结构定义
***************************************************************************************************/


/**************************************************************************************************
* 全局变量声明、定义
***************************************************************************************************/


/**************************************************************************************************
* 私有变量声明、定义
***************************************************************************************************/


/**************************************************************************************************
* 私有函数声明、定义
***************************************************************************************************/


/**************************************************************************************************
* 全局函数声明、定义
***************************************************************************************************/

/*************************************************************************************//**
*\n 函数名称： netcan_open()
*\n 功能描述：
*\n            open CAN接口
*\n 输入参数：
*\n            const char *dev  : 	设备名字符串,"can0" or "can1"
*\n            int bitrate		: 	波特率， 单位为Bps
*\n            int filter_num   : 	滤波表项个数(0~64)
*\n            struct canmsg_filter *filter_tab :  滤波表(可以为NULL)
*\n 输出参数:
*\n            can_handle *phandler :  句柄指针
*\n
*\n 返 回 值:
*\n           0成功;  -1 失败
*\n -----------------------------------------------------------------------------------
*\n  版本:   修改人:       修改日期:        描述:
*\n  V0.01 罗先能        2021.4.7     创建
*\n  V0.02 罗先能        2021.7.7     添加 can_handle *phandle 参数
*****************************************************************************************/
int netcan_open(const char *dev, int bitrate,
				int filter_num, struct canmsg_filter *filter_tab,
				/*out*/ struct can_handle *handle)
{
	struct ifreq ifr;
	struct sockaddr_can addr;
	int family = PF_CAN, type = SOCK_RAW, proto = CAN_RAW;
	int state, num, i;
	int s;
	//struct can_handle *handle;
	struct can_filter *actual_filter;

	// 初始化读写锁
	pthread_rwlock_init(&(handle->lock), NULL);

	if ((filter_num != 0)  && (NULL == filter_tab))
	{
		debug_error("%s: error filter_tab \n", dev);
		//return -1;
		goto error_exit;
	}

	if (bitrate < 10000 || bitrate > 1000000)
	{
		debug_error("%s: error bitrate %ubps\n", dev, bitrate);
		//return -1;
		goto error_exit;
	}
	debug_printf("%s: bitrate %ubps\n", dev, bitrate);

	if (can_get_state(dev, &state) < 0)
	{
		debug_error("%s: failed to get state \n", dev);
		//return -1;
		goto error_exit;
	}

	if (state != CAN_STATE_STOPPED && can_do_stop(dev) < 0)
	{
		debug_error("%s: failed to stop\n", dev);
		//return -1;
		goto error_exit;
	}

	if (can_set_bitrate(dev, bitrate) < 0)
	{
		debug_error("failed to set bitrate of %s to %u\n", dev, bitrate);
		//return -1;
		goto error_exit;
	}

	if (can_do_start(dev) < 0)
	{
		debug_error("%s: failed to start\n", dev);
		//return -1;
		goto error_exit;
	}

	if ((s = socket(family, type, proto)) < 0)
	{
		debug_error("socket() < 0\n");
		//return -1;
		goto error_exit;
	}

	addr.can_family = family;
	strncpy(ifr.ifr_name, dev, 8);
	ioctl(s, SIOCGIFINDEX, &ifr);       //指定can设备
	addr.can_ifindex = ifr.ifr_ifindex;

//	if ((s = socket(family, type, proto)) < 0)
//	{
//		debug_error("Create socket of %s error\n", dev);
//		return NULL;
//	}

	num = (filter_num > 64) ? 64: filter_num;
	num = (num < 1)         ? 1 : num ;

	actual_filter = (struct can_filter *)malloc(sizeof(struct can_filter) * num);
	if (actual_filter == NULL)
	{
		debug_error("malloc can filter failed\n");
		close(s);
		//return -1;
		goto error_exit;
	}

	if (filter_num == 0)
	{
		num = 1;
		actual_filter->can_id = 0;
		actual_filter->can_mask = CAN_RTR_FLAG;
	}
	else
	{
		for (i = 0; i < num; i++)
		{
			actual_filter[i].can_mask = (filter_tab->can_mask & CAN_EXTEND_MASK) | CAN_EFF_FLAG | CAN_RTR_FLAG;
			if (filter_tab->can_id & CAN_EXTEND_FLAG)
				actual_filter[i].can_id = (filter_tab->can_id & CAN_EXTEND_MASK) | CAN_EFF_FLAG;
			else
				actual_filter[i].can_id = filter_tab->can_id & CAN_EXTEND_MASK;
			filter_tab++;
		}
	}

	if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, actual_filter,
	               sizeof(struct can_filter) * num) != 0)
	{
		debug_error("set %s filter failed\n", dev);
		close(s);
		free(actual_filter);
		//return -1;
		goto error_exit;
	}
	free(actual_filter);

	/* struct timeval timeout = {3,0};
	setsockopt(s, SOL_CAN_RAW, SO_SNDTIMEO, (char *)&timeout, sizeof(struct timeval)); */

	if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0)
	{
		debug_error("%s: bind failed\n", dev);
		close(s);
		//return -1;
		goto error_exit;
	}

//	handle = (struct can_handle *)malloc(sizeof(struct can_handle));
//	if (handle == NULL)
//	{
//		close(s);
//		return NULL;
//	}

	handle->socket = s;
	strncpy(handle->dev_name, dev, 32);

	//fcntl(s, F_SETFL, O_NONBLOCK);  // 非阻塞方式;
	fcntl(s, F_SETFL, FNDELAY);       // 非阻塞方式;
	return 0;


error_exit:
	return -1;
}



/*************************************************************************************//**
*\n 函数名称： netcan_close()
*\n 功能描述：
*\n            关闭can接口
*\n 输入参数：
*\n            struct can_handle *handle : can句柄
*\n 输出参数:
*\n
*\n 返 回 值:
*\n           0 成功; -1 失败; -n     错误码
*\n -----------------------------------------------------------------------------------
*\n  版本:   修改人:       修改日期:        描述:
*\n  V0.01 罗先能        2021.4.7     创建
*****************************************************************************************/
int  netcan_close(struct can_handle *handle)
{
	int state;

	if (handle == NULL)
		return -1;
	if(handle->socket == -1)
		return -1;

	close(handle->socket);
	pthread_rwlock_wrlock(&(handle->lock));
	handle->socket = -1;
	pthread_rwlock_unlock(&(handle->lock));
	if (can_get_state(handle->dev_name, &state) < 0)
	{
		debug_error("%s: failed to get state \n", handle->dev_name);
		// free(handle);
		return -1;
	}

	if (state != CAN_STATE_STOPPED && can_do_stop(handle->dev_name) < 0)
	{
		// free(handle);
		debug_error("%s: failed to stop\n", handle->dev_name);
		return -1;
	}
	// free(handle);
	return 0;
}


/*************************************************************************************//**
*\n 函数名称： netcan_write()
*\n 功能描述：
*\n            发送can报文
*\n 输入参数：
*\n            struct can_handle *handle : can句柄
*\n            unsigned int id			 : can id (扩展帧 + CAN_EXTEND_FLAG)
*\n            unsigned char *data       : 发送数据buffer
*\n            unsigned int bytes        : 数据个数byte单位, (1 ~ 8)bytes
*\n 输出参数:
*\n
*\n 返 回 值:
*\n           bytes 成功; -1 失败; -n     错误码
*\n -----------------------------------------------------------------------------------
*\n  版本:   修改人:       修改日期:        描述:
*\n  V0.01 罗先能        2021.4.7     创建
*****************************************************************************************/
int  netcan_write(struct can_handle *handle, unsigned int id,
				unsigned char  *data, unsigned int bytes)
{
	int ret;
	struct can_frame frame;

	if (handle == NULL)
	{
		debug_error("handle == NULL \n");
		return -1;
	}
	if(handle->socket == -1)
	{
		// debug_error("handle->socket == -1\n");
		return -1;
	}


	if (bytes > 8)
		bytes = 8;

	frame.can_id = id;
	frame.can_dlc = bytes;
	memcpy(frame.data, data, bytes);

	pthread_rwlock_wrlock(&(handle->lock));
	ret = write(handle->socket, &frame, sizeof(frame));
	pthread_rwlock_unlock(&(handle->lock));

	return ret;
}


/*************************************************************************************//**
*\n 函数名称： netcan_read()
*\n 功能描述：
*\n            读取can报文
*\n 输入参数：
*\n            struct can_handle *handle : can句柄
*\n
*\n 输出参数:
*\n            unsigned int *id			 : can id (扩展帧 + CAN_EXTEND_FLAG)
*\n            unsigned char *data       : 数据buffer
*\n            unsigned char *bytes       : 数据个数 （可以为NULL）
*\n
*\n 返 回 值:
*\n           数据个数; -1 失败; -n 错误码
*\n -----------------------------------------------------------------------------------
*\n  版本:   修改人:       修改日期:        描述:
*\n  V0.01  罗先能        2021.4.8        创建
*****************************************************************************************/
int netcan_read(struct can_handle *handle,
			unsigned int *can_id, unsigned char *data, unsigned char  *bytes)
{
	struct can_frame frame;

	if (NULL == handle || (NULL == can_id) || (NULL == data))
	{
		debug_error("NULL == handle || (NULL == id) || (NULL == data) \n");
		return -1;
	}
	if(handle->socket == -1)
	{
		// debug_error("handle->socket == -1\n");
		return -1;
	}


	int ret = read(handle->socket, &frame, sizeof(frame));
	if(ret <= 0)
	{
		// debug_error("read() == %d\n", ret);
		return -1;
	}

	*can_id = frame.can_id;
	ret     = frame.can_dlc;
	memcpy(data, frame.data, ret);
	if (NULL != bytes)
		*bytes = ret;

#if 0
	// 调试信息, 打印数据
	debug_printf("");
	printf("can[0x%08x] = ", frame.can_id);
	for (int i = 0; i < 8; ++i)
	{
		printf("0x%02x ", frame.data[i]);
	}
	printf("\n");
#endif

	return  ret;
}




